home *** CD-ROM | disk | FTP | other *** search
- /*
- * tkMacFont.c --
- *
- * Contains the Macintosh implementation of the platform-independant
- * font package interface.
- *
- * Copyright (c) 1990-1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * SCCS: @(#) tkMacFont.c 1.49 97/05/14 18:47:46
- */
-
- #include <Windows.h>
- #include <Strings.h>
- #include <Fonts.h>
- #include <Resources.h>
-
- #include "tkMacInt.h"
- #include "tkFont.h"
- #include "tkPort.h"
-
- /*
- * The following structure represents the Macintosh's' implementation of a
- * font.
- */
-
- typedef struct MacFont {
- TkFont font; /* Stuff used by generic font package. Must
- * be first in structure. */
- short family;
- short size;
- short style;
- } MacFont;
-
- static GWorldPtr gWorld = NULL;
-
- static TkFont * AllocMacFont _ANSI_ARGS_((TkFont *tkfont,
- Tk_Window tkwin, int family, int size, int style));
-
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkpGetNativeFont --
- *
- * Map a platform-specific native font name to a TkFont.
- *
- * Results:
- * The return value is a pointer to a TkFont that represents the
- * native font. If a native font by the given name could not be
- * found, the return value is NULL.
- *
- * Every call to this procedure returns a new TkFont structure,
- * even if the name has already been seen before. The caller should
- * call TkpDeleteFont() when the font is no longer needed.
- *
- * The caller is responsible for initializing the memory associated
- * with the generic TkFont when this function returns and releasing
- * the contents of the generics TkFont before calling TkpDeleteFont().
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- TkFont *
- TkpGetNativeFont(
- Tk_Window tkwin, /* For display where font will be used. */
- CONST char *name) /* Platform-specific font name. */
- {
- short family;
-
- if (strcmp(name, "system") == 0) {
- family = GetSysFont();
- } else if (strcmp(name, "application") == 0) {
- family = GetAppFont();
- } else {
- return NULL;
- }
-
- return AllocMacFont(NULL, tkwin, family, 0, 0);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkpGetFontFromAttributes --
- *
- * Given a desired set of attributes for a font, find a font with
- * the closest matching attributes.
- *
- * Results:
- * The return value is a pointer to a TkFont that represents the
- * font with the desired attributes. If a font with the desired
- * attributes could not be constructed, some other font will be
- * substituted automatically.
- *
- * Every call to this procedure returns a new TkFont structure,
- * even if the specified attributes have already been seen before.
- * The caller should call TkpDeleteFont() to free the platform-
- * specific data when the font is no longer needed.
- *
- * The caller is responsible for initializing the memory associated
- * with the generic TkFont when this function returns and releasing
- * the contents of the generic TkFont before calling TkpDeleteFont().
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- TkFont *
- TkpGetFontFromAttributes(
- TkFont *tkFontPtr, /* If non-NULL, store the information in
- * this existing TkFont structure, rather than
- * allocating a new structure to hold the
- * font; the existing contents of the font
- * will be released. If NULL, a new TkFont
- * structure is allocated. */
- Tk_Window tkwin, /* For display where font will be used. */
- CONST TkFontAttributes *faPtr) /* Set of attributes to match. */
- {
- char buf[257];
- size_t len;
- short family, size, style;
-
- if (faPtr->family == NULL) {
- family = 0;
- } else {
- CONST char *familyName;
-
- familyName = faPtr->family;
- if (strcasecmp(familyName, "Times New Roman") == 0) {
- familyName = "Times";
- } else if (strcasecmp(familyName, "Courier New") == 0) {
- familyName = "Courier";
- } else if (strcasecmp(familyName, "Arial") == 0) {
- familyName = "Helvetica";
- }
-
- len = strlen(familyName);
- if (len > 255) {
- len = 255;
- }
- buf[0] = (char) len;
- memcpy(buf + 1, familyName, len);
- buf[len + 1] = '\0';
- GetFNum((StringPtr) buf, &family);
- }
-
- size = faPtr->pointsize;
- if (size <= 0) {
- size = GetDefFontSize();
- }
-
- style = 0;
- if (faPtr->weight != TK_FW_NORMAL) {
- style |= bold;
- }
- if (faPtr->slant != TK_FS_ROMAN) {
- style |= italic;
- }
- if (faPtr->underline) {
- style |= underline;
- }
-
- return AllocMacFont(tkFontPtr, tkwin, family, size, style);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkpDeleteFont --
- *
- * Called to release a font allocated by TkpGetNativeFont() or
- * TkpGetFontFromAttributes(). The caller should have already
- * released the fields of the TkFont that are used exclusively by
- * the generic TkFont code.
- *
- * Results:
- * None.
- *
- * Side effects:
- * TkFont is deallocated.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- TkpDeleteFont(
- TkFont *tkFontPtr) /* Token of font to be deleted. */
- {
- ckfree((char *) tkFontPtr);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkpGetFontFamilies --
- *
- * Return information about the font families that are available
- * on the display of the given window.
- *
- * Results:
- * interp->result is modified to hold a list of all the available
- * font families.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- TkpGetFontFamilies(
- Tcl_Interp *interp, /* Interp to hold result. */
- Tk_Window tkwin) /* For display to query. */
- {
- MenuHandle fontMenu;
- int i;
- char itemText[257];
-
- fontMenu = NewMenu(1, "\px");
- AddResMenu(fontMenu, 'FONT');
-
- for (i = 1; i < CountMItems(fontMenu); i++) {
- /*
- * Each item is a pascal string. Convert it to C and append.
- */
- GetMenuItemText(fontMenu, i, (unsigned char *) itemText);
- itemText[itemText[0] + 1] = '\0';
- Tcl_AppendElement(interp, &itemText[1]);
- }
- DisposeMenu(fontMenu);
- }
-
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkMacIsCharacterMissing --
- *
- * Given a tkFont and a character determines whether the character has
- * a glyph defined in the font or not. Note that this is potentially
- * not compatible with Mac OS 8 as it looks at the font handle
- * structure directly. Looks into the character array of the font
- * handle to determine whether the glyph is defined or not.
- *
- * Results:
- * Returns a 1 if the character is missing, a 0 if it is not.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- TkMacIsCharacterMissing(
- Tk_Font tkfont, /* The font we are looking in. */
- unsigned int searchChar) /* The character we are looking for. */
- {
- MacFont *fontPtr = (MacFont *) tkfont;
- FMInput fm;
- FontRec **fontRecHandle;
-
- fm.family = fontPtr->family;
- fm.size = fontPtr->size;
- fm.face = fontPtr->style;
- fm.needBits = 0;
- fm.device = 0;
- fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1;
-
- fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult;
- return *(short *) ((long) &(*fontRecHandle)->owTLoc
- + ((long)((*fontRecHandle)->owTLoc + searchChar
- - (*fontRecHandle)->firstChar) * sizeof(short))) == -1;
- }
-
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_MeasureChars --
- *
- * Determine the number of characters from the string that will fit
- * in the given horizontal span. The measurement is done under the
- * assumption that Tk_DrawChars() will be used to actually display
- * the characters.
- *
- * Results:
- * The return value is the number of characters from source that
- * fit into the span that extends from 0 to maxLength. *lengthPtr is
- * filled with the x-coordinate of the right edge of the last
- * character that did fit.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_MeasureChars(
- Tk_Font tkfont, /* Font in which characters will be drawn. */
- CONST char *source, /* Characters to be displayed. Need not be
- * '\0' terminated. */
- int numChars, /* Maximum number of characters to consider
- * from source string. */
- int maxLength, /* If > 0, maxLength specifies the longest
- * permissible line length; don't consider any
- * character that would cross this
- * x-position. If <= 0, then line length is
- * unbounded and the flags argument is
- * ignored. */
- int flags, /* Various flag bits OR-ed together:
- * TK_PARTIAL_OK means include the last char
- * which only partially fit on this line.
- * TK_WHOLE_WORDS means stop on a word
- * boundary, if possible.
- * TK_AT_LEAST_ONE means return at least one
- * character even if no characters fit. */
- int *lengthPtr) /* Filled with x-location just after the
- * terminating character. */
- {
- short staticWidths[128];
- short *widths;
- CONST char *p, *term;
- int curX, termX, curIdx, sawNonSpace;
- MacFont *fontPtr;
- CGrafPtr saveWorld;
- GDHandle saveDevice;
-
- if (numChars == 0) {
- *lengthPtr = 0;
- return 0;
- }
-
- if (gWorld == NULL) {
- Rect rect = {0, 0, 1, 1};
-
- if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) {
- panic("NewGWorld failed in Tk_MeasureChars");
- }
- }
- GetGWorld(&saveWorld, &saveDevice);
- SetGWorld(gWorld, NULL);
-
- fontPtr = (MacFont *) tkfont;
- TextFont(fontPtr->family);
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
- if (maxLength <= 0) {
- *lengthPtr = TextWidth(source, 0, numChars);
- SetGWorld(saveWorld, saveDevice);
- return numChars;
- }
-
- if (numChars > maxLength) {
- /*
- * Assume that all chars are at least 1 pixel wide, so there's no
- * need to measure more characters than there are pixels. This
- * assumption could be refined to an iterative approach that would
- * use that as a starting point and try more chars if necessary (if
- * there actually were some zero-width chars).
- */
-
- numChars = maxLength;
- }
- if (numChars > SHRT_MAX) {
- /*
- * If they are trying to measure more than 32767 chars at one time,
- * it would require several separate measurements.
- */
-
- numChars = SHRT_MAX;
- }
-
- widths = staticWidths;
- if (numChars >= sizeof(staticWidths) / sizeof(staticWidths[0])) {
- widths = (short *) ckalloc((numChars + 1) * sizeof(short));
- }
-
- MeasureText((short) numChars, source, widths);
-
- if (widths[numChars] <= maxLength) {
- curX = widths[numChars];
- curIdx = numChars;
- } else {
- p = term = source;
- curX = termX = 0;
-
- sawNonSpace = !isspace(UCHAR(*p));
- for (curIdx = 1; ; curIdx++) {
- if (isspace(UCHAR(*p))) {
- if (sawNonSpace) {
- term = p;
- termX = widths[curIdx - 1];
- sawNonSpace = 0;
- }
- } else {
- sawNonSpace = 1;
- }
- if (widths[curIdx] > maxLength) {
- curIdx--;
- curX = widths[curIdx];
- break;
- }
- p++;
- }
- if (flags & TK_PARTIAL_OK) {
- curIdx++;
- curX = widths[curIdx];
- }
- if ((curIdx == 0) && (flags & TK_AT_LEAST_ONE)) {
- /*
- * The space was too small to hold even one character. Since at
- * least one character must always fit on a line, return the width
- * of the first character.
- */
-
- curX = TextWidth(source, 0, 1);
- curIdx = 1;
- } else if (flags & TK_WHOLE_WORDS) {
- /*
- * Break at last word that fits on the line.
- */
-
- if ((flags & TK_AT_LEAST_ONE) && (term == source)) {
- /*
- * The space was too small to hold an entire word. This
- * is the only word on the line, so just return the part of th
- * word that fit.
- */
-
- ;
- } else {
- curIdx = term - source;
- curX = termX;
- }
- }
- }
-
- if (widths != staticWidths) {
- ckfree((char *) widths);
- }
-
- *lengthPtr = curX;
-
- SetGWorld(saveWorld, saveDevice);
-
- return curIdx;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_DrawChars --
- *
- * Draw a string of characters on the screen.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information gets drawn on the screen.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_DrawChars(
- Display *display, /* Display on which to draw. */
- Drawable drawable, /* Window or pixmap in which to draw. */
- GC gc, /* Graphics context for drawing characters. */
- Tk_Font tkfont, /* Font in which characters will be drawn;
- * must be the same as font used in GC. */
- CONST char *source, /* Characters to be displayed. Need not be
- * '\0' terminated. All Tk meta-characters
- * (tabs, control characters, and newlines)
- * should be stripped out of the string that
- * is passed to this function. If they are
- * not stripped out, they will be displayed as
- * regular printing characters. */
- int numChars, /* Number of characters in string. */
- int x, int y) /* Coordinates at which to place origin of
- * string when drawing. */
- {
- MacFont *fontPtr;
- MacDrawable *macWin;
- RGBColor macColor, origColor;
- GWorldPtr destPort;
- CGrafPtr saveWorld;
- GDHandle saveDevice;
- short txFont, txFace, txSize;
- BitMapPtr stippleMap;
-
- fontPtr = (MacFont *) tkfont;
- macWin = (MacDrawable *) drawable;
-
- destPort = TkMacGetDrawablePort(drawable);
- GetGWorld(&saveWorld, &saveDevice);
- SetGWorld(destPort, NULL);
-
- TkMacSetUpClippingRgn(drawable);
- TkMacSetUpGraphicsPort(gc);
-
- txFont = tcl_macQdPtr->thePort->txFont;
- txFace = tcl_macQdPtr->thePort->txFace;
- txSize = tcl_macQdPtr->thePort->txSize;
- GetForeColor(&origColor);
-
- if ((gc->fill_style == FillStippled
- || gc->fill_style == FillOpaqueStippled)
- && gc->stipple != None) {
- Pixmap pixmap;
- GWorldPtr bufferPort;
-
- stippleMap = TkMacMakeStippleMap(drawable, gc->stipple);
-
- pixmap = Tk_GetPixmap(display, drawable,
- stippleMap->bounds.right, stippleMap->bounds.bottom, 0);
-
- bufferPort = TkMacGetDrawablePort(pixmap);
- SetGWorld(bufferPort, NULL);
-
- TextFont(fontPtr->family);
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
- if (TkSetMacColor(gc->foreground, &macColor) == true) {
- RGBForeColor(&macColor);
- }
-
- ShowPen();
- MoveTo((short) 0, (short) 0);
- FillRect(&stippleMap->bounds, &qd.white);
- MoveTo((short) x, (short) y);
- DrawText(source, 0, (short) numChars);
-
- SetGWorld(destPort, NULL);
- CopyDeepMask(&((GrafPtr) bufferPort)->portBits, stippleMap,
- &((GrafPtr) destPort)->portBits, &stippleMap->bounds,
- &stippleMap->bounds, &((GrafPtr) destPort)->portRect,
- srcOr, NULL);
-
- /* TODO: this doesn't work quite right - it does a blend. you can't
- * draw white text when you have a stipple.
- */
-
- Tk_FreePixmap(display, pixmap);
- ckfree(stippleMap->baseAddr);
- ckfree((char *)stippleMap);
- } else {
- TextFont(fontPtr->family);
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
- if (TkSetMacColor(gc->foreground, &macColor) == true) {
- RGBForeColor(&macColor);
- }
-
- ShowPen();
- MoveTo((short) (macWin->xOff + x), (short) (macWin->yOff + y));
- DrawText(source, 0, (short) numChars);
- }
-
- TextFont(txFont);
- TextSize(txSize);
- TextFace(txFace);
- RGBForeColor(&origColor);
- SetGWorld(saveWorld, saveDevice);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * AllocMacFont --
- *
- * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
- * Allocates and intializes the memory for a new TkFont that
- * wraps the platform-specific data.
- *
- * Results:
- * Returns pointer to newly constructed TkFont.
- *
- * The caller is responsible for initializing the fields of the
- * TkFont that are used exclusively by the generic TkFont code, and
- * for releasing those fields before calling TkpDeleteFont().
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
- static TkFont *
- AllocMacFont(
- TkFont *tkFontPtr, /* If non-NULL, store the information in
- * this existing TkFont structure, rather than
- * allocating a new structure to hold the
- * font; the existing contents of the font
- * will be released. If NULL, a new TkFont
- * structure is allocated. */
- Tk_Window tkwin, /* For display where font will be used. */
- int family, /* Macintosh font family. */
- int size, /* Point size for Macintosh font. */
- int style) /* Macintosh style bits. */
- {
- char buf[257];
- FontInfo fi;
- MacFont *fontPtr;
- TkFontAttributes *faPtr;
- TkFontMetrics *fmPtr;
- CGrafPtr saveWorld;
- GDHandle saveDevice;
-
- if (gWorld == NULL) {
- Rect rect = {0, 0, 1, 1};
-
- if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) {
- panic("NewGWorld failed in AllocMacFont");
- }
- }
- GetGWorld(&saveWorld, &saveDevice);
- SetGWorld(gWorld, NULL);
-
- if (tkFontPtr == NULL) {
- fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
- } else {
- fontPtr = (MacFont *) tkFontPtr;
- }
-
- fontPtr->font.fid = (Font) fontPtr;
-
- faPtr = &fontPtr->font.fa;
- GetFontName(family, (StringPtr) buf);
- buf[UCHAR(buf[0]) + 1] = '\0';
- faPtr->family = Tk_GetUid(buf + 1);
- faPtr->pointsize = size;
- faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
- faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
- faPtr->underline = ((style & underline) != 0);
- faPtr->overstrike = 0;
-
- fmPtr = &fontPtr->font.fm;
- TextFont(family);
- TextSize(size);
- TextFace(style);
- GetFontInfo(&fi);
- fmPtr->ascent = fi.ascent;
- fmPtr->descent = fi.descent;
- fmPtr->maxWidth = fi.widMax;
- fmPtr->fixed = (CharWidth('i') == CharWidth('w'));
-
- fontPtr->family = (short) family;
- fontPtr->size = (short) size;
- fontPtr->style = (short) style;
-
- SetGWorld(saveWorld, saveDevice);
-
- return (TkFont *) fontPtr;
- }
-
-